package org.raymond.iworks.gateway.filter;

import lombok.extern.slf4j.Slf4j;
import org.raymond.iworks.commons.constants.CacheConstants;
import org.raymond.iworks.core.holder.CacheHolder;
import org.raymond.iworks.core.holder.UserIdContext;
import org.raymond.iworks.core.utils.RequestUtil;
import org.raymond.iworks.gateway.filter.support.FilterOrder;
import org.raymond.iworks.gateway.filter.support.GatewayContext;
import org.raymond.iworks.gateway.utils.ReactiveRequestContextHolder;
import org.reactivestreams.Publisher;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponseDecorator;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

@Slf4j
public class CleanFilter implements GlobalFilter, Ordered {
    private static final String adminLogoutPath = "/admin/user/logout";
    @Autowired
    private CacheHolder cacheHolder;

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        return chain.filter(exchange.mutate().response(cleaner(exchange)).build())
                .contextWrite(ctx -> ctx.delete(ReactiveRequestContextHolder.CONTEXT_KEY))
                .doFinally(s -> exchange.getAttributes().remove(GatewayContext.CACHE_GATEWAY_CONTEXT));
    }

    @Override
    public int getOrder() {
        return FilterOrder.CleanFilter;
    }

    private ServerHttpResponseDecorator cleaner(ServerWebExchange exchange){
        ServerHttpRequest request = exchange.getRequest();
        String requestUri = RequestUtil.getRelativePath(request);
        return new ServerHttpResponseDecorator(exchange.getResponse()){
            public Mono<Void> writeWith(Publisher<? extends DataBuffer> body){
                Long currentUserId = UserIdContext.getUserId();
                Object tokenObj = cacheHolder.get(CacheConstants.CACHE_TOKEN +currentUserId);
                if(tokenObj==null){
                    tokenObj = RequestUtil.resolve(exchange.getRequest());
                }
                UserIdContext.clear();
                if(tokenObj instanceof String token && isLogout(requestUri)){
                    cacheHolder.del(CacheConstants.CACHE_CERT + token);
                    cacheHolder.del(CacheConstants.CACHE_TOKEN + currentUserId);
                }
                return getDelegate().writeWith(body);
            }
        };
    }

    private boolean isLogout(String requestPath){
        return adminLogoutPath.equalsIgnoreCase(requestPath);
    }
}
